#include "stdafx.h"

#include "input/joystick.h"
#include "core/event.h"

namespace natrium {
	namespace input {
		Joystick::Joystick(unsigned int id):
			mJoystickID(id),
			mPosition(nullptr),
			mButtonState(nullptr)
		{
			mNumAxes = glfwGetJoystickParam(id, GLFW_AXES);
			mNumButtons = glfwGetJoystickParam(id, GLFW_BUTTONS);

			if (mNumAxes > 0)
				mPosition = new float[mNumAxes];

			if (mNumButtons > 0)
				mButtonState = new unsigned char[mNumButtons];
		}

		Joystick::~Joystick() {
			if (mPosition)
				delete[] mPosition;

			if (mButtonState)
				delete[] mButtonState;
		}

		void Joystick::update() {
			//make a snapshot of the current state
			std::vector<float> oldPosition;
			std::vector<unsigned char> oldButtonState;
				
			for (unsigned int i = 0; i < mNumAxes; ++i)
				oldPosition.push_back(mPosition[i]);
			for (unsigned int i = 0; i < mNumButtons; ++i)
				oldButtonState.push_back(mButtonState[i]);

			//update the current values
			glfwGetJoystickPos(mJoystickID, mPosition, mNumAxes);
			glfwGetJoystickButtons(mJoystickID, mButtonState, mNumButtons);

			//look for and broadcast changed values
			core::EventChannel chan;

			for (unsigned int i = 0; i < mNumAxes; ++i) {
				if (oldPosition[i] != mPosition[i]) {
					chan.broadcast(Moved(mJoystickID, std::move(oldPosition), mPosition));
					break;
				}
			}

			for (unsigned int i = 0; i < mNumButtons; ++i) {
				if (mButtonState[i] != oldButtonState[i]) {
					if (mButtonState[i] == GLFW_PRESS)
						chan.broadcast(ButtonPressed(mJoystickID, i));
					else //always released
						chan.broadcast(ButtonReleased(mJoystickID, i));
				}
			}
		}

		Joystick::Moved::Moved(unsigned int id, std::vector<float>&& oldPosition, float* newPosition):
			mJoystickID(id),
			mOldPosition(std::move(oldPosition))
		{
			for (size_t i = 0; i < mOldPosition.size(); ++i) {
				float value = newPosition[i];

				mCurrentPosition.push_back(value);
				mDelta.emplace_back(value - mOldPosition[i]);
			}
		}

		Joystick::ButtonPressed::ButtonPressed(unsigned int id, unsigned int button):
			mButtonID(button),
			mJoystickID(id)
		{
		}

		Joystick::ButtonReleased::ButtonReleased(unsigned int id, unsigned int button):
			mButtonID(button),
			mJoystickID(id)
		{
		}

		unsigned int Joystick::getJoystickID() const {
			return mJoystickID;
		}

		unsigned int Joystick::getNumAxes() const {
			return mNumAxes;
		}

		unsigned int Joystick::getNumButtons() const {
			return mNumButtons;
		}

		float Joystick::getAxis(unsigned int index) const {
			assert(index < mNumAxes);
			return mPosition[index];
		}

		float* Joystick::getPosition() const {
			assert(mPosition != nullptr);
			return mPosition;
		}

		unsigned char Joystick::getButton(unsigned int buttonIndex) const {
			assert(buttonIndex < mNumButtons);
			return mButtonState[buttonIndex];
		}


		bool Joystick::isPressed(unsigned int buttonIndex) const {
			assert(buttonIndex < mNumButtons);
			return (mButtonState[buttonIndex] == GLFW_PRESS);
		}
	}
}